/*
	File:	video/Texture.hpp
	Date:	2013-06-09
	Author:	Asteroth
*/


#ifndef __ZEN_SHADER_UNIFORMS_HPP__
#define __ZEN_SHADER_UNIFORMS_HPP__

#include <map>

#include "../gl.hpp"

namespace zen {

	namespace video {

		class ShaderUniforms {

		public:

			static const GLenum GENERIC_INPUT = 0;
			static const GLenum MODEL_VIEW_MATRIX = 1;
			static const GLenum PROJECTION_MATRIX = 2;
			static const GLenum MODEL_VIEW_PROJECTION_MATRIX = 3;
			static const GLenum SAMPLER_2D_0 = 4;
			static const GLenum COUNT = 5;

			// these must match the constants.
			static const std::string uniformNames[ShaderUniforms::COUNT];


		private:

			std::map<std::string, std::pair<GLenum, GLint> > uniforms;
			std::map<GLenum, std::string> types;
			bool changed;


		public:

			ShaderUniforms(): uniforms(), types(), changed(false) {}

			inline bool isChanged() const { return changed; }
			inline void setChanged() { changed = true; }

			inline bool setUniform(const GLenum type, const std::string &name, const GLint location = -1) {
				if (type < 0 || type >= ShaderUniforms::COUNT || name.empty() || location < -1)
					return false;
				this->types[type] = name;
				this->uniforms[name] = std::pair<GLenum, GLint>(type, location);
				changed = true;
				return true;
			}

			inline GLint getLocation(const GLenum type) {
				std::map<GLenum, std::string>::iterator iter = types.find(type);
				return iter == types.end() ? -1 : getLocation(iter->second);
			}
			inline GLint getLocation(const std::string &name) {
				std::map<std::string, std::pair<GLenum, GLint> >::iterator iter = uniforms.find(name);
				return iter == uniforms.end() ? -1 : iter->second.second;
			}

			inline void relinkUniforms(GLuint programHandle, bool forceRelink = false) {
				if (changed || forceRelink)
					for (std::map<std::string, std::pair<GLenum, GLint> >::iterator iter = uniforms.begin(); iter != uniforms.end(); iter++)
						iter->second.second = glGetUniformLocation(programHandle, iter->first.c_str());
				changed = false;
			}

		};


	} // namespace video

} // namespace zen

#endif // __ZEN_SHADER_UNIFORMS_HPP__
